<html>
    <head>
        <title>
            计算属性
        </title>
    </head>
    <body>
        <script>
            // 计算属性
                /*
                     模板中的表达式虽然非常的便利，但是他们的设计目的只是用于"简单计算"。
                    在模板中放入太多的逻辑会让模板过重，且难以维护。
                */
                 // 例如：
                    /*
                        <div id="example">
                            {{message.split(''),reverse().join('')}}
                        </div>
                        在这个地方，模板不在是简单的"声明式逻辑"。
                        你必须看一段时间才能意识到，这里是想要显示变量message的翻转字符串。
                        但是，当你想在模板的多处包含此翻转字符串时，就会更加难以处理。

                         所以，  对于任何复杂逻辑，你都应该使用 "计算属性"
                    */

                  //★一、 基础例子：
                        /*
                            <div id="example">
                                <p>Original message: "{{ message }}"</p>
                                <p>Computed reversed message: "{{ reversedMessage }}"</p>
                            </div>
                        */
                         var vm=new Vue({
                            el:'#example',
                            data:{
                                message:'Hello'
                            },
                            computed:{
                                // 计算属性的getter
                                reversedMessage:function(){
                                    return this.message.split('').reverse().join('');
                                }
                            }
                         });
                         /*
                            这里我们声明了一个计算属性 "reversedMessage" 
                            我们提供的函数将作为property vm.revertedMessage的getter函数；

                            你可以打开浏览器的控制台，自行修改例子中的 vm.reversedMessage 的vm。 会发现，vm.reversedMessage
                            的值始终取决于vm.message的值。

                            你可以像绑定普通property一样在模板中绑定计算属性。Vue知道 vm.reversedMessage 依赖于 vm.message,
                            因此当 vm.message发生改变时，所有依赖vm.reversedMessage的绑定也会更新。

                            而且最妙的是我们已经一声明的方式创建了这种依赖关系： 计算属性的getter函数是没有副作用的,这使它更易于测试和理解。
                         */

                    // ★二、计算属性 vs 方法
                    
                            // 你可能注意到我们医科通过在表达式中调用方法来达到同样的效果：
                               /* <p>Reversed message:"{{ reversedMessage() }}"</p>*/
                            
                            /*
                                我们可以经同一函数定义为一个"方法" 而不是"计算属性"。
                                两种方式的最终结果确实是完全相同的。
                                然而，不同的是 "计算属性是基于他们的响应式依赖缓存的。" 只在相关相应式依赖发生改变时他们才会重新求值。
                                这就意味着，"只要message还没有发生改变，多次访问reversedMessage计算属性会立即返回之前的计算结果，而不必再次执行getter函数。"

                                这也同样意味着下面的计算属性将不再更新，因为Date.now()不是响应式依赖：
                            */
                                    computed:{
                                        now:function(){
                                            return Date.now();
                                        }
                                    }
                            /*
                                相比之下，每当触发"重新渲染"时，调用方法将"总会"再次执行函数。

                                也就是说计算属性每一次计算完成后，会缓存起来，只要依赖的响应式属性值没有发生变化，就会返回缓存值。

                                只有依赖的响应式属性值发生了变化，计算属性才会重新计算，然后再次缓存起来。
                            */

                    // ★三、计算属性 vs 侦听属性
                            /*
                                Vue提供了一种更通用的方式来观察和响应Vue实例上的数据变动: "监听属性"。
                                当你有一些数据需要随着其他数据变动而变动时，你很容易滥用 "watch" 。
                                然而，通常更好的做法是使用计算属性而不是命令式的 watch 回调。
                            */

                            /*
                                    eg:
                                        <div id="demo">{{ fullName }}</div>
                            */
                                    var vm=new Vue({
                                        el:'#demo',
                                        data:{
                                            firstName:'Foo',
                                            lastName:'Bar',
                                            fullName:'Foo Bare'
                                        },
                                        watch:{
                                            firstName:function(val){
                                                this.fullName=val+' '+this.lastName;
                                            },
                                            lastName:function(val){
                                                this.fullName=this.firstName +' '+val;
                                            }
                                        }
                                    });
                                // 上面的代码是命令式重复的。将它与计算属性的版本进行比较：
                                    var vm=new Vue({
                                        el:'#demo',
                                        data:{
                                            firstName:'Foo',
                                            lastName:'Bar'
                                        },
                                        computed:{
                                            fullName:function(){
                                                return this.firstName+' '+this.lastName;
                                            }
                                        }
                                    });

                    // ★四、计算属性的 setter(设置器函数)
                                /*
                                    计算属性默认只有getter,
                                    不过在需要时你也可以提供一个 setter (设置器函数)
                                */
                                 computed:{
                                    fullName:{
                                        // getter
                                        get:function (){
                                            return this.firstName+' '+this.lastName;
                                        },
                                        // setter
                                        set:function(newValue){
                                            var names = newValue.split('');
                                            this.firstName=names[0];
                                            this.lastName=names[names.length-1]
                                        }
                                    }
                                 }
                                 /*
                                    现在，再运行 vm.fullName ='John Doe'时，setter 函数会被调用, vm.firstName 和 vm.lastName 也会被相应的更新。
                                 */
        </script>            
    </body>
</html>